/*
 *  IrrationalElection.cpp
 *  VMF
 *
 *  Created by bdm on 7/2/10.
 *  Copyright 2010 Rochester Institute of Technology. All rights reserved.
 *
 */

#include <cstdlib>
#include <ctime>
#include <cmath>
#include <sstream>
#include "IrrationalElection.h"

// IrrationalElection - default constructor
IrrationalElection::IrrationalElection() : Election<IrrationalVote>(), scores_() {}

// IrrationalElection
IrrationalElection::IrrationalElection( const set<string>& candidates ) : Election<IrrationalVote>( candidates ), scores_() { init(); }

// IrrationalElection
IrrationalElection::IrrationalElection( const set<string>& candidates, const multiset< IrrationalVote >& votes ) : Election<IrrationalVote>( candidates, votes ), scores_() { init(); }

// validate_vote
int IrrationalElection::validate_vote( const IrrationalVote& vote ) const {
    map<pair<string,string>,int> prefs = vote.get_preferences();
    pair<string,string> p;
    set<string>::iterator i = candidates_.begin(), j = i;
    while( i != candidates_.end() ) {
        ++j;
        while( j != candidates_.end() ) {
            p.first = *i;
            p.second = *j;
            if( *i != *j ) {
                if( prefs.find( p ) != prefs.end() ) {
                    int n = prefs.find( p )->second;    
                    if( n < 0 || n > 1 ) {
                        return 0;
                    }
                }
                else {
                    return 0;
                }
            }
            else {
                if( prefs.find( p ) != prefs.end() )
                    return 0;
            }
            ++j;
        }
        j = ++i;
    }
    return 1;
}

// clear_scores
void IrrationalElection::clear_scores() {
    scores_.clear();
    pair<string,string> p;
    set<string>::iterator i = candidates_.begin(), j = i;
    while( i != candidates_.end() ) {
        ++j;
        while( j != candidates_.end() ) {
            if( i != j ) {
                p.first = *i;
                p.second = *j;
                scores_[p] = 0;
            }
            ++j;
        }
        j = ++i;
    }
}

// run_election
string IrrationalElection::run_election() {
    stringstream ret;
    if( !votes_counted() ) {
        count_votes();
    }
    ret << "(r,c) means that the candidate for the given row beats the candidate for the given column that many times.\n";
    set<string>::iterator c1 = candidates_.begin(), c2;
    
    c2 = c1;
    int max_len = 0;
    int s;
    
    // Find the string of maximum length in the candidate set.
    while( c2 != candidates_.end() ) {
        s = c2->size();
        if( s > max_len ) {
            max_len = s;
        }
        ++c2;
    }
    
    // Make sure that the string of maximum length is not less than the highest
    // possible number.
    s = (int)log( candidates_.size() * votes_.size() );
    if( max_len < s ) {
        max_len = s;
    }
    
    // Pad the length by two spaces
    max_len += 2;
    
    // draw the top of matrix.
    ret << setw( max_len ) << " ";
    c2 = c1;
    while( c2 != candidates_.end() ) {
        ret << setw( max_len ) << *c2;
        ++c2;
    }
    
    ret << "\n";
    
    // Draw the rest of the matrix
    pair<string,string> m;
    while( c1 != candidates_.end() ) {
        m.first = *c1;
        c2 = candidates_.begin();
        ret << setw( max_len ) << *c1;
        while( c2 != candidates_.end() ) {
            if( c1 != c2 ) {
                m.second = *c2;
                ret << setw( max_len ) << scores_[m];
            }
            else {
                ret << setw( max_len ) << "-";
            }
            ++c2;
        }
        ret << "\n";
        ++c1;
    }
    
    // Display the winners, if any.
    set<string> winners = get_winners();
    
    if( winners.size() ) {
        set<string>::iterator l = winners.begin();
        ret << "\nWinners:";
        while( l != winners.end() ) {
            ret << " " << *l;
            l++;
        }
    } else {
        ret << "There is no winner in this election.";
    }
    
    return ret.str();
}

void IrrationalElection::add_random_votes( unsigned int n, int printvotes ) {
    multiset<IrrationalVote> votes;
    for( unsigned int i = 0; i < n; ++i ) {
        vector< pair<string,string> > remaining_pairs;
        set<string>::iterator s = candidates_.begin(), t;
        pair<string,string> m;
        while( s != candidates_.end() ) {
            t = s;
            m.first = *s;
            while( ++t != candidates_.end() ) {
                m.second = *t;
                remaining_pairs.push_back( m );
            }
            ++s;
        }
        vector< pair<string,string> >::iterator j = remaining_pairs.begin();
        map<pair<string,string>,int> v;
        while( j != remaining_pairs.end() ) {
            srand( time(NULL) );
            int score = rand() % 2;
            v[*j] = score;
            v[pair<string,string>(j->second,j->first)] = (score + 1) % 2;
            ++j;
        }
        IrrationalVote iv( candidates_, v );
        add_vote( iv );
        votes.insert( iv );
    }

    if( printvotes ) {
        multiset<IrrationalVote>::iterator i = votes.begin();
        //TODO: Finish me.
    }
}
